package br.unifor.mia.olio;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import br.unifor.mia.olio.xml.ExecutionList;
import br.unifor.mia.olio.xml.ExecutionModel;
import br.unifor.mia.olio.xml.summary.BenchResult;
import br.unifor.mia.olio.xml.summary.Operation;

/**
 * Session Bean implementation class Session
 */
@Stateless(mappedName = "SessionRemote")
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class Session implements SessionRemote {

	@PersistenceContext(name = "OlioTestAnaliserEJB")
	EntityManager em;
	private Logger logger = Logger.getLogger(this.getClass().getName());

	@TransactionAttribute(TransactionAttributeType.SUPPORTS)
	public List<Execution> findAllExecution() {
		return em.createNamedQuery("findAll", Execution.class).getResultList();
	}
	
	@TransactionAttribute(TransactionAttributeType.SUPPORTS)
	public List<InstanceType> findAllInstanceType() {
		return em.createNamedQuery("findAllInstanceType", InstanceType.class).getResultList();
	}
	
	@TransactionAttribute(TransactionAttributeType.SUPPORTS)
	public List<Execution> findByFields(String strDataInicial, String strDataFinal, String[] strUsers, String[] instanceType) {
		String strQuery = "select OBJECT(o) from Execution o ";
		
		
		SimpleDateFormat format = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
		
		Date dataInicial = null;
		Date dataFinal = null;
		List<Integer> users = null;
		List<Long> instanceTypes = null;
		
		try {
			dataInicial = format.parse(strDataInicial+" 00:00:01");
		} catch (ParseException e) {
			logger.severe("Data inicial inv�lida "+strDataInicial);
		}
		
		try {
			dataFinal = format.parse(strDataFinal+" 23:59:59");
		} catch (ParseException e) {
			logger.severe("Data inicial inv�lida "+strDataFinal);
		}
		
		if(strUsers != null && strUsers.length >= 0){
			users = new ArrayList<Integer>(strUsers.length);
			
			for (String user : strUsers) {
				users.add(new Integer(user));
			}
		}
		
		if(instanceType != null && instanceType.length >= 0){
			instanceTypes = new ArrayList<Long>(instanceType.length);
			
			for (String str : instanceType) {
				instanceTypes.add(new Long(str));
			}
		}
		
		boolean first = true;
		
		if(dataInicial != null){
			if(first){
				first = false;
				strQuery += " where (o.when >= :dataInicial)";
			}
		}
		
		if(dataFinal != null){
			if(first){
				first = false;
				strQuery += " where (o.when <= :dataFinal)";
			}else{
				strQuery += " and (o.when <= :dataFinal)";
			}
		}
		
		if(users != null){
			if(first){
				first = false;
				strQuery += " where (o.users in (:users))";
			}else{
				strQuery += " and (o.users in (:users))";
			}
		}
		
		if(instanceTypes != null){
			if(first){
				first = false;
				strQuery += " where (o.instanceType.id in (:instanceTypes))";
			}else{
				strQuery += " and (o.instanceType.id in (:instanceTypes))";
			}
		}
		
		strQuery += " order by o.description, o.users, o.when";
		
		logger.info(strQuery);
		
		Query query = em.createQuery(strQuery);
		
		if(dataInicial != null){
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(dataInicial);
			query.setParameter("dataInicial", calendar, TemporalType.TIMESTAMP);
		}
		
		if(dataFinal != null){
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(dataFinal);
			query.setParameter("dataFinal", calendar, TemporalType.TIMESTAMP);
		}
		
		if(users != null){
			query.setParameter("users", users);
		}
		
		if(instanceTypes != null){
			query.setParameter("instanceTypes", instanceTypes);
		}
		
		
		if(first){
			return findAllExecution();
		}else{
			return (List<Execution>)query.getResultList();
		}
		
		
		
	}

	public BenchResult getBenchResult(String id, String ip) {
		BenchResult result = null;
		try {
			JAXBContext jc = JAXBContext.newInstance(BenchResult.class);
			Unmarshaller um = jc.createUnmarshaller();
			URL url = new URL("http://" + ip + ":9980/output/" + id
					+ "/summary.xml");
			result = (BenchResult) um.unmarshal(url);
		} catch (JAXBException e) {
			logger.log(Level.SEVERE, "erro nao identificado", e);
		} catch (MalformedURLException e) {
			logger.log(Level.SEVERE, "faban server not available", e);
		}

		return result;
	}
	
	@TransactionAttribute(TransactionAttributeType.SUPPORTS)
	public Execution loadExecution(Long id) {
		System.out.println("id ["+id+"]");
		return em.find(Execution.class, id);
	}

	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void loadExecutions(String ip) {

		String strData = null;
		try {

			logger.info("Carregando o ip " + ip);

			String content = ExecutionList.loadUrl("http://" + ip
					+ ":9980/controller/results/list");

			ExecutionList list = new ExecutionList(content);

			list.run();

			// "02/21/11 19:38:37"
			SimpleDateFormat format = new SimpleDateFormat("MM/dd/yy HH:mm:ss");

			Execution execBean;

			for (ExecutionModel model : list.getExecutions()) {
				execBean = new Execution();
				execBean.setName(model.getName());
				execBean.setDescription(model.getDescription());
				
				execBean.setUsers(new Integer(model.getUsers()));

				Calendar data = Calendar.getInstance();
				strData = model.getDate();

				Date date = format.parse(strData);

				data.setTime(date);

				execBean.setWhen(data);

				if (!(model.getResult().contains("killed.png") || model
						.getResult().contains("incomplete.png"))) {

					Boolean passed = true;

					BenchResult result = getBenchResult(execBean.getName(), ip);

					for (Operation operation : result.getDriverSummary()
							.getOperations()) {
						passed &= operation.isPassed();
					}

					if (passed) {
						for (Operation operation : result.getDriverSummary()
								.getResponseTimes()) {
							passed &= operation.isPassed();
						}

						if (passed) {
							for (Operation operation : result
									.getDriverSummary().getDelayTimes()) {
								passed &= operation.isPassed();
							}

							if (passed) {
								int i = 0;
								for (Operation operation : result
										.getDriverSummary().getDelayTimes()) {

									if (operation.isPassed()) {
										i++;
									}
									passed = i >= 3;

								}

								if (!passed) {
									logger.severe(execBean.getName()
											+ " VERIFICAR ");
								}
							} else {
								logger.info(execBean.getName()
										+ " perdeu na TERCEIRA parte (tempo)");
							}

						} else {
							logger.info(execBean.getName()
									+ " perdeu na SEGUNDA parte (tempo)");
						}

					} else {
						logger.info(execBean.getName()
								+ " perdeu na PRIMEIRA parte");
					}

					execBean.setSuccess(passed);
					
					String description = execBean.getDescription();
					if(description.indexOf("|")!=-1){
						logger.info(description);
						//StringTokenizer token = new StringTokenizer(description, "|");
						//description = token.nextToken();
					}else{
						description = "INDETERMINADO";
					}
					
					execBean.setInstanceType(getInstanceType(description));

					em.persist(execBean);

				} else {
					execBean.setSuccess(Boolean.FALSE);
				}

			}

		} catch (IOException e) {
			logger.log(Level.SEVERE, "erro ao carregar a url", e);
		} catch (ParseException e) {
			logger.log(Level.SEVERE, "data mal formada " + strData, e);
			e.printStackTrace();
		}

	}
	
	private InstanceType getInstanceType(String name){
		Query query = em.createNamedQuery("findByNameInstanceType", InstanceType.class);
		
		InstanceType lInstanceType = null;
		try{
			
		
			lInstanceType = (InstanceType)query.setParameter("name", name).getSingleResult();
		}
		catch(NoResultException e){
			lInstanceType = new InstanceType();
			lInstanceType.setName(name);
			
			em.persist(lInstanceType);
		}
		
		return lInstanceType;
		
	}
	
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public Execution createExecution(Execution model){
		Execution execBean = new Execution();
		execBean.setName(model.getName());
		execBean.setDescription(model.getDescription());
		
		execBean.setUsers(new Integer(model.getUsers()));

		execBean.setInstanceType(getInstanceType(model.getInstanceType().getName()));
		execBean.setSuccess(model.getSuccess());

		execBean.setWhen(model.getWhen());
		
		em.persist(execBean);
		
		return execBean;
	}
	
	@TransactionAttribute(TransactionAttributeType.SUPPORTS)
	public List<Execution> getExecutions(List<Long> ids){
		
		
		Query query = em.createNamedQuery("findByIds", Execution.class);
		
		query.setParameter("ids", ids);
		
		return (List<Execution>)query.getResultList();

	}

}
